#include "videoglwidget.h"


VideoGLWidget::VideoGLWidget(QWidget* parent)
    : QOpenGLWidget(parent)
{
    qDebug() << "VideoGLWidget::VideoGLWidget";
    mVideoSink = new QVideoSink(this);
    connect(mVideoSink, &QVideoSink::videoFrameChanged, this, [this](const QVideoFrame& frame) {
        // qDebug() << "Updating frame";
        QVideoFrame cloneFrame(frame);
        cloneFrame.map(QVideoFrame::ReadOnly);
        QImage image = cloneFrame.toImage();
        if (image.format() != QImage::Format_RGBA8888) {
            image = image.convertToFormat(QImage::Format_RGBA8888);
        }
        currentFrame = image.copy();
        cloneFrame.unmap();
        update();
    });
    qDebug() << "VideoGLWidget::VideoGLWidget finish";
}

VideoGLWidget::~VideoGLWidget()
{
    if (program != nullptr) {
        delete program;
    }
}

void VideoGLWidget::initializeGL() {
    qDebug() << "VideoGLWidget::initializeGL";
    if (program != nullptr) {
        delete program;
        program = nullptr;
    }
    initializeOpenGLFunctions();

    // Initialize shaders
    program = new QOpenGLShaderProgram(this);
    program->addShaderFromSourceCode(QOpenGLShader::Vertex,
                                    "#version 330 core\n"
                                    "layout(location = 0) in vec4 vertex;\n"
                                    "out vec2 texCoord;\n"
                                    "void main() {\n"
                                    "   gl_Position = vertex;\n"
                                    "   texCoord = vertex.xy * 0.5 + 0.5;\n"
                                    "}\n");

    program->addShaderFromSourceCode(QOpenGLShader::Fragment,
                                    "#version 330 core\n"
                                    "in vec2 texCoord;\n"
                                    "uniform sampler2D videoTex;\n"
                                    "out vec4 fragColor;\n"
                                    "void main() {\n"
                                    "   fragColor = texture(videoTex, vec2(texCoord.x, 1.0 - texCoord.y));\n" // Flip the y-coordinate
                                    "}\n");

    program->link();


    glGenTextures(1, &textureId);
    glBindTexture(GL_TEXTURE_2D, textureId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);

    // Set up vertex data
    static const GLfloat vertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        1.0f,  1.0f,
        -1.0f,  1.0f
    };

    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    qDebug() << "VideoGLWidget::initializeGLFinish";
}

void VideoGLWidget::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if (!currentFrame.isNull()) {
        glBindTexture(GL_TEXTURE_2D, textureId);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, currentFrame.width(), currentFrame.height(),
                     0, GL_RGBA, GL_UNSIGNED_BYTE, currentFrame.bits());

        program->bind();
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        program->release();
    }
}

void VideoGLWidget::resizeGL(int w, int h) {
    glViewport(0, 0, w, h);
}
